#include "stdafx.h"
#include "BaseApplication.h"

//#include "res/resource.h"

//#include <OgrePlugin.h>

//-------------------------------------------------------------------------------------
BaseApplication::BaseApplication(void)
	: mRoot(0),
	mCamera(0),
	mSceneMgr(0),
	mWindow(0),
	mCursorWasVisible(false),
	mShutDown(false),
	mInputManager(0),
	mMouse(0),
	mKeyboard(0)
{
}

//-------------------------------------------------------------------------------------
BaseApplication::~BaseApplication(void)
{
	//Remove ourself as a Window listener
	Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this);
	windowClosed(mWindow);
	delete mRoot;
}

//-------------------------------------------------------------------------------------
bool BaseApplication::configure(void)
{
	// Show the configuration dialog and initialise the system
	// You can skip this and use root.restoreConfig() to load configuration
	// settings if you were sure there are valid ones saved in ogre.cfg
	// Grab the OpenGL RenderSystem, or exit
	if(mRoot->restoreConfig() || mRoot->showConfigDialog())
	{
		// If returned true, user clicked OK so initialise
		// Here we choose to let the system create a default rendering window by passing 'true'
		mWindow = mRoot->initialise(true, "Ogre Move Test");

		// Let's add a nice window icon
		HWND hwnd;
		mWindow->getCustomAttribute("WINDOW", (void*)&hwnd);
		LONG iconID   = (LONG)LoadIcon( GetModuleHandle(0), MAKEINTRESOURCE(IDI_APPICON) );
		SetClassLong( hwnd, GCL_HICON, iconID );

		return true;
	}
	else
	{
		return false;}
}
//-------------------------------------------------------------------------------------
void BaseApplication::chooseSceneManager(void)
{
	// Get the SceneManager, in this case a generic one
	mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC);
}
//-------------------------------------------------------------------------------------
void BaseApplication::createCamera(void)
{
	// Create the camera
	mCamera = mSceneMgr->createCamera("PlayerCam");

	// Position it at 500 in Z direction
	mCamera->setPosition(Ogre::Vector3(0,0,100));
	// Look back along -Z
	mCamera->lookAt(Ogre::Vector3(0,0,0));
	mCamera->setNearClipDistance(5);

	//mCameraMan = new OgreBites::SdkCameraMan(mCamera);   // create a default camera controller
}
//-------------------------------------------------------------------------------------
void BaseApplication::createFrameListener(void)
{
	mDebugOverlay = Ogre::OverlayManager::getSingleton().getByName("Core/DebugOverlay");

	Ogre::LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
	OIS::ParamList pl;
	size_t windowHnd = 0;
	std::ostringstream windowHndStr;

	mWindow->getCustomAttribute("WINDOW", &windowHnd);
	windowHndStr << windowHnd;
	pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));

	mInputManager = OIS::InputManager::createInputSystem( pl );

	mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, false ));
	mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, true ));

	mMouse->setEventCallback(this);
	// You may remove the comment, if you want to test with PS Move only
	// mKeyboard->setEventCallback(this);

	//Set initial mouse clipping size
	windowResized(mWindow);

	showDebugOverlay(true);

	//Register as a Window listener
	Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this);

}
//-------------------------------------------------------------------------------------
void BaseApplication::destroyScene(void)
{
}
//-------------------------------------------------------------------------------------
void BaseApplication::createViewports(void)
{
	// Create one viewport, entire window
	Ogre::Viewport* vp = mWindow->addViewport(mCamera);
	vp->setBackgroundColour(Ogre::ColourValue(0,0,0));

	// Alter the camera aspect ratio to match the viewport
	mCamera->setAspectRatio(
		Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));
}
//-------------------------------------------------------------------------------------
void BaseApplication::setupResources(void)
{
	// Only add the minimally required resource locations to load up SDKTrays and the Ogre head mesh
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/packs/Sinbad.zip", "Zip", "General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/fonts", "FileSystem", "General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/MyGUI_Media", "FileSystem", "General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/packs/cube.zip", "Zip", "General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/packs/Derins_Sword.zip", "Zip", "General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/packs/Mutagon_Kornel.zip", "Zip", "General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/packs/Mutagon_Misi.zip", "Zip", "General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/packs/Mutagon_Vinicz.zip", "Zip", "General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/packs/penguin.zip", "Zip", "General");
	
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/packs/Agyu.zip", "Zip", "General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/packs/AgyuGolyo.zip", "Zip", "General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/packs/Fountain.zip", "Zip", "General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/packs/Hordo1.zip", "Zip", "General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/packs/Hordo2.zip", "Zip", "General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/packs/MeatBall.zip", "Zip", "General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/packs/OgreCastle.zip", "Zip", "General");

	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/materials","FileSystem","General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/textures","FileSystem","General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/materials/programs","FileSystem","General");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/CEGUI_datafiles/imagesets","FileSystem","Imagesets");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/CEGUI_datafiles/fonts","FileSystem","Fonts");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/CEGUI_datafiles/schemes","FileSystem","Schemes");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/CEGUI_datafiles/looknfeel","FileSystem","LookNFeel");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/CEGUI_datafiles/layouts","FileSystem","Layouts");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/particles", "FileSystem", "General");
}
//-------------------------------------------------------------------------------------
void BaseApplication::createResourceListener(void)
{

}
//-------------------------------------------------------------------------------------
void BaseApplication::loadResources(void)
{
	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}
//-------------------------------------------------------------------------------------
void BaseApplication::go(void)
{

	if (!setup())
		return;

	mRoot->startRendering();

	// clean up
	destroyScene();
}
//-------------------------------------------------------------------------------------
bool BaseApplication::setup(void)
{
	mRoot = new Ogre::Root("");

	// A list of required plugins
	Ogre::StringVector required_plugins;
	required_plugins.push_back("D3D9 RenderSystem");
	required_plugins.push_back("GL RenderSystem");
	required_plugins.push_back("Octree & Terrain Scene Manager");
	required_plugins.push_back("ParticleFX");

	// List of plugins to load
	Ogre::StringVector plugins_toLoad;
	plugins_toLoad.push_back("RenderSystem_Direct3D9");
	plugins_toLoad.push_back("RenderSystem_GL");
	plugins_toLoad.push_back("Plugin_OctreeSceneManager");
	plugins_toLoad.push_back("Plugin_ParticleFX");

	// Load the OpenGL RenderSystem and the Octree SceneManager plugins
	for (Ogre::StringVector::iterator j = plugins_toLoad.begin(); j != plugins_toLoad.end(); j++)
	{
#ifdef _DEBUG
		mRoot->loadPlugin(*j + Ogre::String("_d"));
#else
		mRoot->loadPlugin(*j);
#endif;
	}

	// Check if the required plugins are installed and ready for use
	// If not: exit the application
	Ogre::Root::PluginInstanceList ip = mRoot->getInstalledPlugins();
	for (Ogre::StringVector::iterator j = required_plugins.begin(); j != required_plugins.end(); j++)
	{
		bool found = false;
		// try to find the required plugin in the current installed plugins
		for (Ogre::Root::PluginInstanceList::iterator k = ip.begin(); k != ip.end(); k++)
		{
			Ogre::String pluginName=(*k)->getName();
			if (pluginName == *j)
			{
				found = true;
				break;
			}
		}
		if (!found)  // return false because a required plugin is not available
		{
			return false;
		}
	}

	setupResources();

	bool carryOn = configure();
	if (!carryOn) return false;

	chooseSceneManager();
	createCamera();
	createViewports();

	// Initialization of ExampleFrameListener variables
	mTranslateVector = Ogre::Vector3::ZERO;
	mCurrentSpeed = 0;
	mStatsOn = true;
	mNumScreenShots = 0;
	mMoveScale = 0.0f;
	mRotScale=0.0f, 
		mTimeUntilNextToggle =0; 
	mFiltering = Ogre::TFO_BILINEAR;
	mAniso=1;
	mSceneDetailIndex=0;
	mMoveSpeed =100; 
	mRotateSpeed=36;
	mDebugOverlay=0;


	// Set default mipmap level (NB some APIs ignore this)
	Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);

	// Create any resource listeners (for loading screens)
	createResourceListener();
	// Load resources
	loadResources();

	createFrameListener();

	// Create the scene
	createScene();

	return true;
};
//-------------------------------------------------------------------------------------
bool BaseApplication::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
	if(mWindow->isClosed())	return false;


	mSpeedLimit = mMoveScale * evt.timeSinceLastFrame;

	//Need to capture/update each device
	mKeyboard->capture();
	mMouse->capture();

	Ogre::Vector3 lastMotion = mTranslateVector;

	//Check if one of the devices is not buffered

	// You may remove the comment, if you want to test with mouse
	//if( !mMouse->buffered() || !mKeyboard->buffered() )
	if( !mKeyboard->buffered() )
	{
		// one of the input modes is immediate, so setup what is needed for immediate movement
		if (mTimeUntilNextToggle >= 0)
			mTimeUntilNextToggle -= evt.timeSinceLastFrame;

		// Move about 100 units per second
		mMoveScale = mMoveSpeed * evt.timeSinceLastFrame;
		// Take about 10 seconds for full rotation
		mRotScale = mRotateSpeed * evt.timeSinceLastFrame;

		mRotX = 0;
		mRotY = 0;
		mTranslateVector = Ogre::Vector3::ZERO;

	}

	if( !mKeyboard->buffered() )
		if( processUnbufferedKeyInput(evt) == false )
			return false;

	// You may remove the comment, if you want to test with mouse
	/*
	if( !mMouse->buffered() )
	if( processUnbufferedMouseInput(evt) == false )
	return false;
	*/

	// ramp up / ramp down speed
	if (mTranslateVector == Ogre::Vector3::ZERO)
	{
		// decay (one third speed)
		mCurrentSpeed -= evt.timeSinceLastFrame * 0.3;
		mTranslateVector = lastMotion;
	}
	else
	{
		// ramp up
		mCurrentSpeed += evt.timeSinceLastFrame;

	}
	// Limit motion speed
	if (mCurrentSpeed > 1.0)
		mCurrentSpeed = 1.0;
	if (mCurrentSpeed < 0.0)
		mCurrentSpeed = 0.0;

	mTranslateVector *= mCurrentSpeed;

	// You may remove the comment, if you want to test with mouse
	if( !mKeyboard->buffered())
		//if( !mMouse->buffered() || !mKeyboard->buffered())
		moveCamera();

	return true;
}
// You may remove the comment, if you want to test with PS Move only
//-------------------------------------------------------------------------------------
/*
bool BaseApplication::keyPressed( const OIS::KeyEvent &arg )
{
if (arg.key == OIS::KC_R)   // cycle polygon rendering mode
{
Ogre::String newVal;
Ogre::PolygonMode pm;

switch (mCamera->getPolygonMode())
{
case Ogre::PM_SOLID:
newVal = "Wireframe";
pm = Ogre::PM_WIREFRAME;
break;
case Ogre::PM_WIREFRAME:
newVal = "Points";
pm = Ogre::PM_POINTS;
break;
default:
newVal = "Solid";
pm = Ogre::PM_SOLID;
}

mCamera->setPolygonMode(pm);
}
else if(arg.key == OIS::KC_F5)   // refresh all textures
{
Ogre::TextureManager::getSingleton().reloadAll();
}
else if (arg.key == OIS::KC_SYSRQ)   // take a screenshot
{
mWindow->writeContentsToTimestampedFile("screenshot", ".jpg");
}
else if (arg.key == OIS::KC_ESCAPE)
{
mShutDown = true;
}


mGUI->injectKeyPress(MyGUI::KeyCode::Enum(arg.key), arg.text);
return true;
}
*/

// You may remove the comment, if you want to test with PS Move only
/*
bool BaseApplication::keyReleased( const OIS::KeyEvent &arg )
{
mGUI->injectKeyRelease(MyGUI::KeyCode::Enum(arg.key));
return true;
}
*/

bool BaseApplication::mouseMoved( const OIS::MouseEvent &arg )
{
	//mGUI->injectMouseMove(arg.state.X.abs, arg.state.Y.abs, arg.state.Z.abs);


	return true;
}

bool BaseApplication::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
	//mGUI->injectMousePress(arg.state.X.abs, arg.state.Y.abs, MyGUI::MouseButton::Enum(id));
	return true;
}

bool BaseApplication::mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
	//mGUI->injectMouseRelease(arg.state.X.abs, arg.state.Y.abs, MyGUI::MouseButton::Enum(id));
	return true;
}

//Adjust mouse clipping area
void BaseApplication::windowResized(Ogre::RenderWindow* rw)
{
	unsigned int width, height, depth;
	int left, top;
	rw->getMetrics(width, height, depth, left, top);

	const OIS::MouseState &ms = mMouse->getMouseState();
	ms.width = width;
	ms.height = height;
}

//Unattach OIS before window shutdown (very important under Linux)
void BaseApplication::windowClosed(Ogre::RenderWindow* rw)
{
	//Only close for window that created OIS (the main window in these demos)
	if( rw == mWindow )
	{
		if( mInputManager )
		{
			mInputManager->destroyInputObject( mMouse );
			mInputManager->destroyInputObject( mKeyboard );

			OIS::InputManager::destroyInputSystem(mInputManager);
			mInputManager = 0;
		}
	}

}

// -- IMPLEMENTAIONS OF THE ExampleFrameListener FUNCTIONS 
bool BaseApplication::processUnbufferedKeyInput(const Ogre::FrameEvent& evt)
{
	Ogre::Real moveScale = mMoveScale;
	if(mKeyboard->isKeyDown(OIS::KC_LSHIFT))
		moveScale *= 10;

	if(mKeyboard->isKeyDown(OIS::KC_A))
		mTranslateVector.x = -moveScale;	// Move camera left

	if(mKeyboard->isKeyDown(OIS::KC_D))
		mTranslateVector.x = moveScale;	// Move camera RIGHT

	if(mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W) )
		mTranslateVector.z = -moveScale;	// Move camera forward

	if(mKeyboard->isKeyDown(OIS::KC_DOWN) || mKeyboard->isKeyDown(OIS::KC_S) )
		mTranslateVector.z = moveScale;	// Move camera backward

	if(mKeyboard->isKeyDown(OIS::KC_PGUP))
		mTranslateVector.y = moveScale;	// Move camera up

	if(mKeyboard->isKeyDown(OIS::KC_PGDOWN))
		mTranslateVector.y = -moveScale;	// Move camera down

	if(mKeyboard->isKeyDown(OIS::KC_RIGHT))
		mCamera->yaw(-mRotScale);

	if(mKeyboard->isKeyDown(OIS::KC_LEFT))
		mCamera->yaw(mRotScale);

	if( mKeyboard->isKeyDown(OIS::KC_ESCAPE) || mKeyboard->isKeyDown(OIS::KC_Q) )
		return false;

	// Return true to continue rendering*/
	return true;
}

// // You may remove the comment, if you want to test with mouse
/*
bool BaseApplication::processUnbufferedMouseInput(const Ogre::FrameEvent& evt)
{

// Rotation factors, may not be used if the second mouse button is pressed
// 2nd mouse button - slide, otherwise rotate
const OIS::MouseState &ms = mMouse->getMouseState();
if( ms.buttonDown( OIS::MB_Right ) )
{
mTranslateVector.x += ms.X.rel * 0.13;
mTranslateVector.y -= ms.Y.rel * 0.13;
}
else
{
mRotX = Ogre::Degree(-ms.X.rel * 0.13);
mRotY = Ogre::Degree(-ms.Y.rel * 0.13);
#if OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
// Adjust the input depending upon viewport orientation
Radian origRotY, origRotX;
switch(mCamera->getViewport()->getOrientation())
{
case Viewport::OR_LANDSCAPELEFT:
origRotY = mRotY;
origRotX = mRotX;
mRotX = origRotY;
mRotY = -origRotX;
break;
case Viewport::OR_LANDSCAPERIGHT:
origRotY = mRotY;
origRotX = mRotX;
mRotX = -origRotY;
mRotY = origRotX;
break;

// Portrait doesn't need any change
case Viewport::OR_PORTRAIT:
default:
break;
}
#endif
}

return true;
}
*/

void BaseApplication::moveCamera()
{
	// Make all the changes to the camera
	// Note that YAW direction is around a fixed axis (freelook style) rather than a natural YAW
	//(e.g. airplane)
	mCamera->yaw(mRotX);
	mCamera->pitch(mRotY);
	mCamera->moveRelative(mTranslateVector);
}


void BaseApplication::showDebugOverlay(bool show)
{
	if (mDebugOverlay)
	{
		if (show)
			mDebugOverlay->show();
		else
			mDebugOverlay->hide();
	}
}
